package com.gitee.wsl.net.ssdp.description.model.xml

import com.gitee.wsl.logger.Logger
import com.gitee.wsl.logger.info
import com.gitee.wsl.net.ssdp.description.model.xml.ServiceStateTable.StateVariable
import kotlin.properties.Delegates
import com.gitee.wsl.net.ssdp.description.xml.XmlElement

/**
 * Detailed service description
 * @param urns              - reference to the UPnP Service Schema
 * @param configId          - configuration number to which the service description belongs
 *                              (must be identical to the one from discovery message)
 * @param specVersion       - @see SpecVersion
 * @param actionList        - @see Action
 * @param serviceStateTable - @see StateVariable
 * @param language      - content description language specified by device
 *
 * @see "https://openconnectivity.org/upnp-specs/UPnP-arch-DeviceArchitecture-v2.0-20200417.pdf", ch.2.5
 */
data class XmlServiceDescription(
    var urns: Map<String, String>,
    var configId: Int? = null,
    val specVersion: SpecVersion,
    val actionList: List<ActionList.Action>? = null,
    val serviceStateTable: List<StateVariable>,
    var language: String = "en"
) {
    companion object{
        /**
         * Facilitates fast and flexible deserialization and conditional validation.
         */
        fun fromXml(xml: XmlElement): XmlServiceDescription {
            var urnsO: Map<String, String> = emptyMap()
            var configIdI: Int? = null
            var specVersionO by Delegates.notNull<SpecVersion>()
            var actionListO: List<ActionList.Action>? = null
            var serviceStateTableO by Delegates.notNull<List<StateVariable>>()

            xml.children?.forEach {
                when (it.tag) {
                    "urns" -> urnsO = it.attributes ?: throw IllegalArgumentException("Invalid service description")
                    "configId" -> configIdI = it.getOrNull<Int>()
                    "specVersion" -> specVersionO = SpecVersion.Companion.fromXml(it)
                    "actionList" -> actionListO = ActionList.fromXml(it)
                    "serviceStateTable" -> serviceStateTableO = ServiceStateTable.fromXml(it)
                    else -> Logger.info("Unexpected tag ${it.tag}")
                }
            }
            return XmlServiceDescription(urnsO, configIdI, specVersionO, actionListO, serviceStateTableO)
        }
        fun XmlElement.toXmlServiceDescription(): XmlServiceDescription = fromXml(this)
    }
}
